package com.iplant.basic.serviceImpl.dao.bfc;

import com.iplant.base.po.OutResult;
import com.iplant.base.po.excel.ExcelSheetData;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.update.CAPoHead;
import com.iplant.basic.service.po.update.CAPoProp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

public class CAPoDAO extends BaseDAO {

    private static CAPoDAO Instance = null;
    private static Logger logger = LoggerFactory.getLogger(CAPoDAO.class);

    private CAPoDAO() {
        super("");
    }

    public static CAPoDAO getInstance() {
        if (Instance == null) {
            Instance = new CAPoDAO();
            Instance.Init();
        }
        return Instance;
    }

    /**
     * 通过Excel数据获取CAPoHead
     */
    public CAPoHead GetCAPoHeadByExcelSheetData(BMSEmployee wLoginUser, ExcelSheetData wExcelSheetData,
                                                OutResult<Integer> wErrorCode) {
        CAPoHead wResult = new CAPoHead();
        try {
            String description = wExcelSheetData.lineData.get(0).colData.get(1);
            String tableName = wExcelSheetData.lineData.get(0).colData.get(3);
            List<String> checkCodeList = GetCheckCodeList(wExcelSheetData);
            boolean isCodeAuto = wExcelSheetData.lineData.get(0).colData.get(7).equals("是");
            String codePrefix = wExcelSheetData.lineData.get(0).colData.get(9);
            int serialCodeNum = StringUtils.parseInt(wExcelSheetData.lineData.get(0).colData.get(11));
            String schema = wExcelSheetData.lineData.get(0).colData.get(13);
            boolean isHasCode = wExcelSheetData.lineData.get(0).colData.get(15).equals("是");
            boolean isHasName = wExcelSheetData.lineData.get(0).colData.get(17).equals("是");
            boolean isHasActive = wExcelSheetData.lineData.get(0).colData.get(19).equals("是");
            boolean isAutoCreateTable = wExcelSheetData.lineData.get(0).colData.get(21).equals("是");
            List<CAPoProp> poPropList = new ArrayList<>();
            CAPoProp wCAPoProp;
            for (int i = 5; i < wExcelSheetData.lineData.size(); i++) {
                List<String> colData = wExcelSheetData.lineData.get(i).colData;
                String fieldName = colData.get(0);
                if (StringUtils.isEmpty(fieldName)) {
                    continue;
                }
                String fieldType = colData.get(1);
                boolean isDBField = colData.get(2).equals("是");
                boolean isQueryField = colData.get(3).equals("是");
                boolean isJoinQuery = colData.get(4).equals("是");
                String joinFieldName = colData.get(5);
                String joinTableName = colData.get(6);
                String joinTableAsName = colData.get(7);
                String joinSchema = colData.get(8);
                String joinMainField = colData.get(9);
                int joinIndex = StringUtils.parseInt(colData.get(10));
                String joinSelfCondition = colData.get(11);
                String multiJoinFieldName = colData.get(12);
                String multiJoinMainField = colData.get(13);
                String multiJoinTableName = colData.get(14);
                String multiJoinSchema = colData.get(15);
                String wDescription = colData.get(16);
                String queryType = colData.get(17);

                wCAPoProp = new CAPoProp(fieldName, fieldType, isDBField, isQueryField, isJoinQuery, joinFieldName,
                        joinTableName, joinTableAsName, joinSchema, joinMainField, joinIndex, joinSelfCondition,
                        multiJoinFieldName, multiJoinMainField, multiJoinTableName, multiJoinSchema, wDescription,
                        queryType);
                poPropList.add(wCAPoProp);
            }

            wResult = new CAPoHead(description, tableName, checkCodeList, isCodeAuto, codePrefix, serialCodeNum,
                    schema, isHasCode, isHasName, isHasActive, isAutoCreateTable, poPropList);
        } catch (Exception ex) {
            logger.error("GetCAPoHeadByExcelSheetData", ex);
        }
        return wResult;
    }

    private List<String> GetCheckCodeList(ExcelSheetData wExcelSheetData) {
        List<String> wResult = new ArrayList<>();
        try {
            String s = wExcelSheetData.lineData.get(0).colData.get(5);
            if (StringUtils.isNotEmpty(s)) {
                wResult.add(s);
            }
            String s2 = wExcelSheetData.lineData.get(1).colData.get(5);
            if (StringUtils.isNotEmpty(s2)) {
                wResult.add(s2);
            }
            String s3 = wExcelSheetData.lineData.get(2).colData.get(5);
            if (StringUtils.isNotEmpty(s3)) {
                wResult.add(s3);
            }
        } catch (Exception ex) {
            logger.error("GetCheckCodeList", ex);
        }
        return wResult;
    }

    /**
     * 获取PoString
     */
    public String GetPoStringByCAPoHead(BMSEmployee wLoginUser, ExcelSheetData wExcelSheetData, CAPoHead wCAPoHead,
                                        OutResult<Integer> wErrorCode) {
        String wResult = "";
        try {
            StringBuilder wSB = new StringBuilder();
            //①解析包名
            String wPackageString = GetPackageString(wCAPoHead, wExcelSheetData);
            wSB.append(wPackageString);
            //②解析导入ipmort
            String wImportString = GetImportString(wCAPoHead);
            wSB.append(wImportString);
            //③解析类注释
            String wClassDecriptionString = GetClassDecriptionString(wCAPoHead);
            wSB.append(wClassDecriptionString);
            //③解析DBBasePO
            String wDBBasePOString = GetDBBasePOString(wCAPoHead, wExcelSheetData);
            wSB.append(wDBBasePOString);
            //④解析class定义
            String wClassString = GetClassString(wCAPoHead, wExcelSheetData);
            wSB.append(wClassString);
            //⑤解析序列号字段
            String wSerialNoString = GetSerialNoString(wCAPoHead, wExcelSheetData);
            wSB.append(wSerialNoString);
            //⑥解析属性列表
            String wPropString = GetPropString(wCAPoHead, wExcelSheetData);
            wSB.append(wPropString);
            //⑦解析Getter和Setter
            String wGetterSetterString = GetGetterSetterString(wCAPoHead, wExcelSheetData);
            wSB.append(wGetterSetterString);
            //⑧收尾
            wSB.append("}");
            //⑧提取结果
            wResult = wSB.toString();
        } catch (Exception ex) {
            logger.error("GetPoStringByCAPoHead", ex);
        }
        return wResult;
    }

    private String GetGetterSetterString(CAPoHead wCAPoHead, ExcelSheetData wExcelSheetData) {
        String wResult = "";
        try {
            StringBuilder wSB = new StringBuilder();
            for (CAPoProp caPoProp : wCAPoHead.PoPropList) {
                wSB.append(StringUtils.Format("    @JsonProperty(\"{0}\")\r\n", caPoProp.FieldName));
                wSB.append(StringUtils.Format("    public {1} get{0}() '{'\r\n", caPoProp.FieldName,
                        caPoProp.FieldType));
                wSB.append(StringUtils.Format("        return {0};\r\n", caPoProp.FieldName));
                wSB.append("    }\r\n\r\n");

                wSB.append(StringUtils.Format("    public void set{0}({2} {1}) '{'\r\n", caPoProp.FieldName,
                        makeFirstCharLowerCase(caPoProp.FieldName), caPoProp.FieldType));
                wSB.append(StringUtils.Format("        {0} = {1};\r\n", caPoProp.FieldName,
                        makeFirstCharLowerCase(caPoProp.FieldName)));
                wSB.append("    }\r\n\r\n");
            }
            wResult = wSB.toString();
        } catch (Exception e) {
            logger.error("APS_CheckPlanNumber_Week", e);
        }
        return wResult;
    }

    public String makeFirstCharLowerCase(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        char firstChar = str.charAt(0);
        char lowerFirstChar = Character.toLowerCase(firstChar);
        return lowerFirstChar + str.substring(1);
    }

    private String GetPropString(CAPoHead wCAPoHead, ExcelSheetData wExcelSheetData) {
        String wResult = "";
        try {
            StringBuilder wSB = new StringBuilder();
            for (CAPoProp caPoProp : wCAPoHead.PoPropList) {
                //①注释
                wSB.append("    /**\r\n");
                wSB.append(StringUtils.Format("     * {0}\r\n", caPoProp.Description));
                wSB.append("     */\r\n");
                //②DBCondition
                if (caPoProp.IsQueryField) {
                    wSB.append("    @DBCondition");
                    if (StringUtils.isNotEmpty(caPoProp.QueryType)) {
                        wSB.append(StringUtils.Format("(CompareType = DBCondition.DBCompareType.{0})",
                                caPoProp.QueryType));
                    }
                    wSB.append("\r\n");
                }
                //③DBFiled
                if (caPoProp.IsDBField) {
                    wSB.append("    @DBField\r\n");
                }
                //④DBJoin
                if (caPoProp.IsJoinQuery) {
                    wSB.append(StringUtils.Format("    @DBJoin(name = \"{0}\", tableName = \"{1}\", " +
                                    "tableAsName = \"{2}\", Schemas = DBSchemas.{3}", caPoProp.JoinFieldName,
                            caPoProp.JoinTableName, caPoProp.JoinTableAsName, caPoProp.JoinSchema));
                    if (StringUtils.isNotEmpty(caPoProp.JoinMainField)) {
                        wSB.append(StringUtils.Format(", MainTableField = \"{0}\"", caPoProp.JoinMainField));
                    }
                    if (caPoProp.JoinIndex > 0) {
                        wSB.append(StringUtils.Format(", JoinIndex = {0}", String.valueOf(caPoProp.JoinIndex)));
                    }
                    if (StringUtils.isNotEmpty(caPoProp.JoinSelfCondition)) {
                        wSB.append(StringUtils.Format(", ConditionalJoin = \"{0}\"", caPoProp.JoinSelfCondition));
                    }
                    wSB.append(")\r\n");
                }
                //⑤DBMultiJoin
                if (StringUtils.isNotEmpty(caPoProp.MultiJoinFieldName)) {
                    wSB.append(StringUtils.Format("    @DBJoinMulti(Name = \"{0}\", MainTableField = \"{1}\", " +
                                    "TableName = \"{2}\", Schemas = DBSchemas.{3})\r\n", caPoProp.MultiJoinFieldName,
                            caPoProp.MultiJoinMainField, caPoProp.MultiJoinTableName, caPoProp.MultiJoinSchema));
                }
                //⑥属性定义
                String wDefaultValue = GetDefaultValue(caPoProp);
                wSB.append(StringUtils.Format("    public {0} {1} = {2};\r\n\r\n", caPoProp.FieldType,
                        caPoProp.FieldName,
                        wDefaultValue));

                wResult = wSB.toString();
            }
        } catch (Exception e) {
            logger.error("GetPropString", e);
        }
        return wResult;
    }

    private String GetDefaultValue(CAPoProp caPoProp) {
        String wResult = "";
        try {
            switch (caPoProp.FieldType) {
                case "int":
                case "Integer":
                    wResult = "0";
                    break;
                case "String":
                    wResult = "\"\"";
                    break;
                case "float":
                case "Float":
                    wResult = "0.0f";
                    break;
                case "double":
                case "Double":
                    wResult = "0.0";
                    break;
                case "Calendar":
                    wResult = "CalendarTool.getBasicDate()";
                    break;
                default:
                    if (caPoProp.FieldType.contains("List")) {
                        wResult = "new ArrayList<>()";
                    } else if (caPoProp.FieldType.contains("Map")) {
                        wResult = "new HashMap<>()";
                    } else {
                        wResult = StringUtils.Format("new {0}()", caPoProp.FieldType);
                    }
                    break;
            }
        } catch (Exception e) {
            logger.error("GetDefaultValue", e);
        }
        return wResult;

    }

    private String GetSerialNoString(CAPoHead wCAPoHead, ExcelSheetData wExcelSheetData) {
        String wResult = "";
        try {
            wResult = "    private static final long serialVersionUID = 1L;\r\n\r\n";
        } catch (Exception e) {
            logger.error("GetSerialNoString", e);
        }
        return wResult;
    }

    private String GetClassString(CAPoHead wCAPoHead, ExcelSheetData wExcelSheetData) {
        String wResult = "";
        try {
            wResult = StringUtils.Format("public class {0} extends BasePO implements Serializable '{'\r\n\r\n",
                    wExcelSheetData.sheetName);
        } catch (Exception e) {
            logger.error("GetClassString", e);
        }
        return wResult;
    }

    private String GetDBBasePOString(CAPoHead wCAPoHead, ExcelSheetData wExcelSheetData) {
        String wResult = "";
        try {
            StringBuilder wSB = new StringBuilder();
            wSB.append(StringUtils.Format("@DBBasePO(TableName = \"{0}\"", wCAPoHead.TableName));
            wSB.append(", CheckName = {");
            for (int i = 0; i < wCAPoHead.CheckCodeList.size(); i++) {
                if (i == wCAPoHead.CheckCodeList.size() - 1) {
                    wSB.append(StringUtils.Format("\"{0}\"", wCAPoHead.CheckCodeList.get(i)));
                } else {
                    wSB.append(StringUtils.Format("\"{0}\", ", wCAPoHead.CheckCodeList.get(i)));
                }
            }
            wSB.append("}");
            wSB.append(StringUtils.Format(", Schemas = DBSchemas.{0}", wCAPoHead.Schema));
            if (wCAPoHead.IsCodeAuto) {
                wSB.append(", CodeAuto = true");
                wSB.append(StringUtils.Format(", CodePrefix = \"{0}\"", wCAPoHead.CodePrefix));
                wSB.append(StringUtils.Format(", CodeNum = {0}", String.valueOf(wCAPoHead.SerialCodeNum)));
            }
            if (!wCAPoHead.IsHasCode) {
                wSB.append(", Code = false");
            }
            if (!wCAPoHead.IsHasName) {
                wSB.append(", Name = false");
            }
            if (!wCAPoHead.IsHasActive) {
                wSB.append(", Active = false");
            }
            if (!wCAPoHead.IsAutoCreateTable) {
                wSB.append(", AutoCreateTable = false");
            }
            wSB.append(")\r\n");
            wResult = wSB.toString();
        } catch (Exception e) {
            logger.error("GetDBBasePOString", e);
        }
        return wResult;
    }

    private String GetClassDecriptionString(CAPoHead wCAPoHead) {
        String wResult = "";
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String currentTime = sdf.format(Calendar.getInstance().getTime());

            StringBuilder wSB = new StringBuilder();
            wSB.append("/**\r\n");
            wSB.append(StringUtils.Format(" * {0}\r\n", wCAPoHead.Description));
            wSB.append(" *\r\n");
            wSB.append(" * @author YouWang·Peng\r\n");
            wSB.append(StringUtils.Format(" * {0}\r\n", currentTime));
            wSB.append(" */\r\n");
            wResult = wSB.toString();
        } catch (Exception e) {
            logger.error("GetClassDecriptionString", e);
        }
        return wResult;
    }

    private String GetImportString(CAPoHead wCAPoHead) {
        String wResult = "";
        try {
            StringBuilder wSB = new StringBuilder();
            wSB.append("import com.fasterxml.jackson.annotation.JsonProperty;\r\n");
            wSB.append("import com.iplant.base.po.BasePO;\r\n");
            wSB.append("import com.iplant.base.po.enums.DBSchemas;\r\n");
            wSB.append("import com.iplant.base.utils.annotation.field.DBField;\r\n");
            wSB.append("import com.iplant.base.utils.annotation.condition.DBCondition;\r\n");
            wSB.append("import com.iplant.base.utils.annotation.join.DBJoin;\r\n");
            if (wCAPoHead.PoPropList.stream().anyMatch(p -> StringUtils.isNotEmpty(p.MultiJoinFieldName))) {
                wSB.append("import com.iplant.base.utils.annotation.join.multi.DBJoinMulti;\r\n");
            }
            wSB.append("import com.iplant.base.utils.annotation.po.DBBasePO;\r\n\r\n");

            wSB.append("import java.io.Serializable;\r\n");
            if (wCAPoHead.PoPropList.stream().anyMatch(p -> p.FieldType.contains("List"))) {
                wSB.append("import java.util.ArrayList;\r\n");
                wSB.append("import java.util.List;\r\n");
            }

            if (wCAPoHead.PoPropList.stream().anyMatch(p -> p.FieldType.contains("Calendar"))) {
                wSB.append("import java.util.Calendar;\r\n");
            }

            if (wCAPoHead.PoPropList.stream().anyMatch(p -> p.FieldType.contains("Map"))) {
                wSB.append("import java.util.Map;\r\n\r\n");
            } else {
                wSB.append("\r\n");
            }

            wResult = wSB.toString();
        } catch (Exception e) {
            logger.error("GetImportString", e);
        }
        return wResult;
    }

    private String GetPackageString(CAPoHead wCAPoHead, ExcelSheetData wExcelSheetData) {
        String wResult = "";
        try {
            wResult = StringUtils.Format("package com.iplant.{0}.service.po.{1};\r\n\r\n",
                    wCAPoHead.Schema.toLowerCase(), wExcelSheetData.sheetName.substring(0, 3).toLowerCase());
        } catch (Exception e) {
            logger.error("GetPackageString", e);
        }
        return wResult;
    }
} 